﻿//#define USE_DYNAMIC_SHAREPOINT
//#define USE_REFLECTION_SHAREPOINT
using System;
using System.Collections.Generic;
using System.Text;
using System.Data.Common;
using System.Reflection;

#if USE_DYNAMIC_SHAREPOINT || USE_REFLECTION_SHAREPOINT
#else
using Microsoft.SharePoint;
#endif

namespace System.Data.SharePoint
{
    public class SharePointDataReader : DbDataReader
    {
        public SharePointDataReader(SharePointCommand command)
        {
            this._command = command;
            this._sharePointList = this._command.Connection.GetSharePointList(this._command.ListUrl);
        }

        public override void Close()
        {            
            this._isClosed = true;
        }

        public override int Depth
        {
            get { throw new NotImplementedException(); }
        }

        public override int FieldCount
        {
            get
            {
                return this._sharePointList.Fields.Count;
            }
        }

        public override System.Collections.IEnumerator GetEnumerator()
        {
            throw new NotImplementedException();
        }

#if USE_DYNAMIC_SHAREPOINT
        public override Type GetFieldType(int ordinal)
        {
            return SharePointConnection.GetFieldType((int)(this._sharePointList.Fields[ordinal].Type));
        }
#elif USE_REFLECTION_SHAREPOINT
#else
        public override Type GetFieldType(int ordinal)
        {
            switch(this._sharePointList.Fields[ordinal].Type)
            {
                case SPFieldType.Guid:
                    {
                        return typeof(Guid);
                        break;
                    }
                case SPFieldType.Counter:
                    {
                        return typeof(long);
                        break;
                    }
                case SPFieldType.Text:
                    {
                        return typeof(string);
                        break;
                    }
                case SPFieldType.DateTime:
                    {
                        return typeof(DateTime);
                        break;
                    }
                case SPFieldType.Boolean:
                    {
                        return typeof(bool);
                        break;
                    }
                case SPFieldType.Integer:
                    {
                        return typeof(int);
                        break;
                    }
                case SPFieldType.Number:
                    {
                        return typeof(decimal);
                        break;
                    }
                default:
                    {
                        return typeof(string);
                    }
            }
            return null;
        }
#endif

        public override string GetDataTypeName(int ordinal)
        {
            throw new NotImplementedException();
        }

        public override bool GetBoolean(int ordinal)
        {
            return Convert.ToBoolean(GetValue(ordinal));
        }

        public override byte GetByte(int ordinal)
        {
            return Convert.ToByte(GetValue(ordinal));
        }

        public override long GetBytes(int ordinal, long dataOffset, byte[] buffer, int bufferOffset, int length)
        {
            throw new NotImplementedException();
        }

        public override char GetChar(int ordinal)
        {
            return Convert.ToChar(GetValue(ordinal));
        }

        public override long GetChars(int ordinal, long dataOffset, char[] buffer, int bufferOffset, int length)
        {
            throw new NotImplementedException();
        }

        public override DateTime GetDateTime(int ordinal)
        {
            return Convert.ToDateTime(GetValue(ordinal));
        }

        public override decimal GetDecimal(int ordinal)
        {
            return Convert.ToDecimal(GetValue(ordinal));
        }

        public override double GetDouble(int ordinal)
        {
            return Convert.ToDouble(GetValue(ordinal));
        }

        public override float GetFloat(int ordinal)
        {
            return Convert.ToSingle(GetValue(ordinal));
        }

        public override Guid GetGuid(int ordinal)
        {
            return new Guid(Convert.ToString(GetValue(ordinal)));
        }

        public override short GetInt16(int ordinal)
        {
            return Convert.ToInt16(GetValue(ordinal));
        }

        public override int GetInt32(int ordinal)
        {
            return Convert.ToInt32(GetValue(ordinal));
        }

        public override long GetInt64(int ordinal)
        {
            return Convert.ToInt64(GetValue(ordinal));
        }

        public override string GetString(int ordinal)
        {
            return Convert.ToString(GetValue(ordinal));
        }

        public override string GetName(int ordinal)
        {
            return this._sharePointList.Fields[ordinal].InternalName;
        }

        private Dictionary<string, int> fieldsDictionary;

        public override int GetOrdinal(string name)
        {
            if (this.fieldsDictionary == null)
            {
                this.fieldsDictionary = new Dictionary<string, int>();
                for (int i = 0; i < this._sharePointList.Fields.Count; i++)
                {
                    this.fieldsDictionary.Add(this._sharePointList.Fields[i].InternalName, i);
                }
            }
            return this.fieldsDictionary[name];
        }

        public override DataTable GetSchemaTable()
        {
            throw new NotImplementedException();
        }

        public override object GetValue(int ordinal)
        {
            try
            {
                return this._sharePointListItemCollection[this._readingIndex][this._sharePointList.Fields[ordinal].Id];
            }
            catch (Exception ex)
            {
                // TODO:
            }
            return null;
        }

        public override int GetValues(object[] values)
        {
            int fieldCount = Math.Min(values.Length, FieldCount);
            for (int i = 0; i < fieldCount; i++)
            {
                values[i] = GetValue(i);
            }
            return fieldCount;
        }

        public override bool HasRows
        {
            get { throw new NotImplementedException(); }
        }

        private bool _isClosed;
        public override bool IsClosed
        {
            get { return this._isClosed; }
        }

        public override bool IsDBNull(int ordinal)
        {
            return (GetValue(ordinal) == null);
        }

        public override bool NextResult()
        {
            // TODO:
            return false;
        }

        public override bool Read()
        {
            if (this._readingState == -1)
            {
                QueryForSharePointListItemCollection();
                if (this._sharePointListItemCollection.Count > 0)
                {
                    this._readingIndex = 0;
                    this._readingState = 1;
                    return true;
                }
                else
                {
                    this._readingIndex = -1;
                    return false;
                }
            }
            else
            {
                this._readingIndex++;
                if (this._readingIndex < this._sharePointListItemCollection.Count)
                {
                    return true;
                }
                else
                {
                    this._readingIndex = -1;
                    this._readingState = -1;
                    return false;
                }
            }
        }

        public override int RecordsAffected
        {
            get { throw new NotImplementedException(); }
        }

        public override object this[string name]
        {
            get { throw new NotImplementedException(); }
        }

        public override object this[int ordinal]
        {
            get { throw new NotImplementedException(); }
        }

        private SharePointCommand _command;

        private int _readingIndex = -1;
        private int _readingState = -1;

#if USE_DYNAMIC_SHAREPOINT
        private dynamic _sharePointList;
        public dynamic SharePointList
        {
            get { return _sharePointList; }
            set { _sharePointList = value; }
        }

        private dynamic _sharePointListItemCollection;
        public dynamic SharePointListItemCollection
        {
            get
            {
                return this._sharePointListItemCollection;
            }
        }

        private void QueryForSharePointListItemCollection()
        {
            dynamic query = SharePointConnection.CreateSPQuery();
            query.Query = this._command.CommandText;
            query.ViewFields = this._command.ViewFields;
            this._sharePointListItemCollection = this._sharePointList.GetItems(query);
        }

#elif USE_REFLECTION_SHAREPOINT
#else
        private SPList _sharePointList;
        public SPList SharePointList
        {
            get { return _sharePointList; }
            set { _sharePointList = value; }
        }

        private SPListItemCollection _sharePointListItemCollection;
        public SPListItemCollection SharePointListItemCollection
        {
            get
            {
                return this._sharePointListItemCollection;
            }
        }

        private void QueryForSharePointListItemCollection()
        {
            SPQuery query = new SPQuery();
            query.Query = this._command.CommandText;
            query.ViewFields = this._command.ViewFields;
            this._sharePointListItemCollection = this._sharePointList.GetItems(query);
        }
#endif

        private string _listUrl;
        public string ListUrl
        {
            get
            {
                return this._listUrl;
            }
            set
            {
                this._listUrl = value;
                if ((this._command != null) && (this._command.Connection != null))
                {
                    if (this.SharePointList == null)
                    {
                        this.SharePointList = this._command.Connection.GetSharePointList(this._listUrl);
                    }
                }
            }
        }
    }
}
